<?php

/**
 * HTML5 Multimedia Framework Class
 * A Highly Customisable Multimedia Framework for Wordpress
 *
 * Copyright (C) 2011 by Christopher John Jackson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * Embed Videos and Audios into respective HTML5 tags, on fail it falls back to
 * FlowPlayer
 *
 * @author cjackson
 */
class html5player {
    const HTML5_TAG = '<!-- Generated by HTML5 Multimedia Framework (http://code.google.com/p/html5videoplayer) -->';

    const minBuggyIOSWebkit = 420;
    const maxBuggyIOSWebkit = 532;
    const maxBuggyIOSWebkitAlt = 534;

    private $url;
    private $root;
    private $flowplayer;
    private $language;
    private $option;
    private $count;
    private $htmlAttribute;
    private $tag;
    private $oembed;
    private $linkGen;
    private $mediaelement;

    public function __construct($url, $siteurl, $root) {
        $this->url['script'] = $url;
        $this->url['site'] = $siteurl;
        $this->root = $root;
        require_once 'inc/flowplayer.class.php';
        require_once 'inc/oembedext.class.php';
        $this->flowplayer = new flowplayer($this->url['script']);
        $this->oembed = new oEmbedExt();
        $this->mediaelement = false;
        $this->defaultLanguage();
        $this->defaultOption();
        $this->defaultHtmlAttribute();
        $this->count = array("video" => 0, "audio" => 0);
        $this->tag = array("video" => "video", "audio" => "audio", "flowplayer" => "flowplayer", "oembed" => "oembed");
        require_once 'inc/typeandlinkgen.class.php';
    }

    private function defaultOption() {
        $this->option = array(
            'xmlMode' => false,
            'videoID' => false,
            'beforeVideo' => '',
            'afterVideo' => '',
            'videoScript' => false,
            'audioID' => false,
            'beforeAudio' => '',
            'afterAudio' => '',
            'audioScript' => false,
            'videoLinkOutside' => false,
            'audioLinkOutside' => false,
            'videoLinkOutsideBefore' => '<p>',
            'videoLinkOutsideAfter' => '</p>',
            'audioLinkOutsideBefore' => '<p>',
            'audioLinkOutsideAfter' => '</p>',
            'downloadLinkDisabled' => false
        );
    }

    public function initMediaElement() {
        require_once 'mediaelement/mediaelement.class.php';
        $this->mediaelement = new mediaelement($this->url['script']);
    }

    public function setMediaElementDir($dir) {
        if ($this->mediaelement) {
            $this->mediaelement->setMediaElementDir($dir);
        }
    }

    private function defaultLanguage() {
        $this->language = array(
            'noVideo' => "No video playback capabilities, please download the video below",
            'noAudio' => "No audio playback capabilities, please download the audio below",
            'downloadVideo' => '<strong>Download Video:</strong>',
            'downloadAudio' => '<strong>Download Audio:</strong>',
            'closedFormat' => 'Closed Format:',
            'openFormat' => 'Open Format:'
        );
    }

    private function defaultHtmlAttribute() {
        $this->htmlAttribute = array(
            'video' => array(
                'controls' => null,
                'preload' => "none"
            ),
            'audio' => array(
                'controls' => null
            )
        );
    }

    public function setVideoAttribute($key, $value) {
        $this->htmlAttribute["video"][strtolower($key)] = $value;
    }

    public function setAudioAttribute($key, $value) {
        $this->htmlAttribute["audio"][strtolower($key)] = $value;
    }

    public function setLanguage($key, $value) {
        $this->language[$key] = $value;
    }

    public function setOption($key, $value) {
        $this->option[$key] = $value;
    }

    public function getOption($key) {
        return $this->option[$key];
    }

    public function setTag($key, $value) {
        $this->tag[$key] = $value;
    }

    public function getTag($key) {
        return $this->tag[$key];
    }

    public function setFlowPlayerOption($key, $value) {
        $this->flowplayer->setOptions($key, $value);
    }

    public function setFlowplayerConfig($json) {
        $jsonTemp = json_decode($json, true);
        if ($this->is_assoc($jsonTemp)) {
            $this->flowplayer->setFlowplayerConfig($jsonTemp);
        } else {
            echo $this->jsonError();
        }
    }

    public function setUserObjectAttribute($expression, $assoc_array) {
        $this->oembed->setUserObjectAttribute($expression, $assoc_array);
    }

    public function setUserObjectParameter($expression, $assoc_array) {
        $this->oembed->setUserObjectParameter($expression, $assoc_array);
    }

    public function oEmbedJSON($data, $array = false) {
        if ($array) {
            $jsonTemp = $array;
        } else {
            if (is_array($data)) {
                $jsonTemp = $this->removeJSONNoise($data[1]);
            } else {
                $jsonTemp = $data;
            }
            unset($data);
            $jsonTemp = json_decode($jsonTemp, true);
        }
        if ($this->is_assoc($jsonTemp)) {
            foreach ($jsonTemp as $key => $value) {
                $json[strtolower($key)] = $value;
            }
            return $this->oembed->oEmbedJSON($json);
        } else {
            return $this->jsonError() . " @ Video Tag";
        }
    }

    public function oembedFilter($html, $url) {
        $this->oembed->parseUrl($url, false, false, $html);
        return $this->oembed->getEmbedCode();
    }

    public function flowPlayerJSON($json, $array = false) {
        if (!$array) {
            if (is_array($json)) {
                $json = $this->removeJSONNoise($json[1]);
            }
            return $this->flowplayer->flowPlayerJSON($json);
        } else {
            return $this->flowplayer->flowPlayerJSON(null, $array);
        }
    }

    public function videoreplace($data) {
        $data = $data[1];
        $data = explode(" ", $data);
        return $this->arrayToOrganisedArrays($data);
    }

    private function removeJSONNoise($data) {
        $jsonTemp = preg_replace('~(&#(8220|8221|8243);|“|”)~', '"', $data);
        unset($data);
        $jsonTemp = preg_replace('#((,){0,1}<(.*?)>){0,}(("){1}(.){0,}(<(.*?)>){1,}(.){0,}("){1}){0,}#i', '$2$4', $jsonTemp);
        $jsonTemp = preg_replace('#("|}|]){1}(,){0,1}(<(.*?)>){0,}("|}|]){1}#i', '$1$2$5', $jsonTemp);
        $jsonTemp = preg_replace('#(.){1}(\n){1}(<(.*?)>){0,1}("){1}#i', '$1$3$5', $jsonTemp);
        return $jsonTemp;
    }

    public function videoreplaceJSON($data, $array = false, $lock = false) {
        if (preg_match("#(webOS|SymbianOS|Nokia|Android)#i", $_SERVER['HTTP_USER_AGENT']) &&
                (defined('WPHTML5_PREVENT_FLASH_LITE') && !$this->option['xmlMode'])) {
            $lock = true;
        }
        if ($array) {
            $jsonTemp = $array;
        } else {
            if (is_array($data)) {
                $jsonTemp = $this->removeJSONNoise($data[1]);
            } else {
                $jsonTemp = $data;
            }
            unset($data);
            $jsonTemp = json_decode($jsonTemp, true);
        }
        if ($this->is_assoc($jsonTemp)) {
            foreach ($jsonTemp as $key => $value) {
                $json[strtolower($key)] = $value;
            }
            unset($jsonTemp);
            if (isset($json["src"])) {
                $json["url"] = $json["src"];
                unset($json["src"]);
            }
            if (!isset($json["url"])) {
                return "ERROR: url/src not specified";
            } elseif ($this->is_assoc($json["url"]) && !is_string($json["url"])) {
                return "ERROR: url/src as object is not allowed";
            }
            if (!is_array($json["url"])) {
                $json['url'] = array($json["url"]);
            }

            if(!isset($json["track"])) {
                $json["track"] = false;
            } elseif (!is_array($json["track"])) {
                $json["track"] = false;
            }

            if (!(isset($json["width"]) && isset($json["height"]))) {
                $json["width"] = false;
                $json["height"] = false;
            } elseif (!(is_numeric($json["width"]) && is_numeric($json["height"]))) {
                $json["width"] = false;
                $json["height"] = false;
            } else {
                $json["width"] = (int) $json["width"];
                $json["height"] = (int) $json["height"];
            }
            if (!isset($json["poster"]) || is_array($json["poster"])) {
                $json["poster"] = false;
            } elseif (!preg_match("#.(jpg|jpeg|png|gif)$#i", $json["poster"])) {
                $json["poster"] = false;
            }
            if ($json["poster"]) {
                $url[0] = $json["poster"];
                $url = $this->urlsCheck($url);
                $json["poster"] = $url[0];
            }
            if (!isset($json["title"]) || is_array($json["title"])) {
                $json["title"] = false;
            } else {
                $json["title"] = htmlspecialchars($json["title"]);
            }
            if (!isset($json["attribute"])) {
                $json["attribute"] = false;
            } elseif (!$this->is_assoc($json["attribute"])) {
                $json["attribute"] = false;
            }

            if (!isset($json["mediaelement"])) {
                $json["mediaelement"] = false;
            } elseif (!$this->is_assoc($json["mediaelement"])) {
                $json["mediaelement"] = false;
            }

            if (isset($json["oembed"]) && !$this->is_assoc($json["oembed"]) && !$lock) {
                $temp = array(
                    "url" => $json["oembed"],
                    "width" => $json["width"],
                    "height" => $json["height"]
                );
                $json["oembed"] = $temp;
                unset($temp);
            } else {
                $json["oembed"] = false;
            }
            return $this->videoCodeGenerator(null, null, $json, $lock);
        } else {
            return $this->jsonError() . " @ Video Tag";
        }
    }

    public function is_assoc($var) {
        return is_array($var) && array_keys($var) !== range(0, sizeof($var) - 1);
    }

    public function jsonError() {
        $json_errors = array(
            JSON_ERROR_NONE => 'No error has occurred',
            JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
            JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
            JSON_ERROR_SYNTAX => 'Syntax error',
        );
        if (function_exists("json_last_error")) {
            return "JSON ERROR: " . $json_errors[json_last_error()];
        } else {
            return "UNKNOWN ERROR: probably syntax error.";
        }
    }

    private function arrayToOrganisedArrays($matches) {
        $videourls = $matches[0];
        $videourls = explode("|", $videourls);
        $videourls = $this->urlsCheck($videourls);
        $ifScore = 1;

        $videooption["poster"] = false;
        //Check for poster url.
        if (isset($matches[$ifScore]) && !is_numeric($matches[$ifScore])) {
            if (preg_match("#.(jpg|jpeg|png|gif)$#i", $matches[$ifScore])) {
                $url[0] = $matches[$ifScore];
                $url = $this->urlsCheck($url);
                $videooption["poster"] = $url[0];
            }
            $ifScore++;
        }

        $videooption["width"] = false;
        $videooption["height"] = false;
        //Check for resolution
        if (isset($matches[$ifScore]) && isset($matches[$ifScore + 1])) {
            if (is_numeric($matches[$ifScore]) && is_numeric($matches[$ifScore + 1])) {
                $videooption["width"] = (int) $matches[$ifScore];
                $videooption["height"] = (int) $matches[$ifScore + 1];
                $ifScore + 2;
            }
        }
        return $this->videoCodeGenerator($videourls, $videooption);
    }

    private function videoCodeGenerator($videourls, $videooption, $JSON = false, $lock = false) {
        if ($JSON) {
            $videourls = $this->urlsCheck($JSON["url"]);
            $width = $JSON["width"];
            $height = $JSON["height"];
            $poster = $JSON["poster"];
            $title = $JSON["title"];
            $attribute = $JSON["attribute"];
            $oembed = $JSON["oembed"];
            $track = $JSON["track"];
            $mediaelement = $JSON["mediaelement"];
            unset($JSON);
        } else {
            $width = $videooption["width"];
            $height = $videooption["height"];
            $poster = $videooption["poster"];
            $title = false;
            $attribute = false;
            $oembed = false;
            $track = false;
            $mediaelement = false;
        }
        if (!isset($this->linkGen)) {
            $this->linkGen = new TypeAndLinkGenclass($this->language['downloadAudio'],
                    $this->language['downloadVideo'], $this->language['openFormat'], $this->language['closedFormat'],
                    $this->meEnabled());
        }
        $sources = '';
        foreach ($videourls as $value) {
            if (!($lock || $oembed)) {
                if ($this->mediaelement) {
                    $videoCompatible = array("url" => $value, "poster" => $poster, "width" => $width, "height" => $height,
                        "title" => $title);
                    $this->mediaelement->videoCompatible($videoCompatible);
                } else {
                    $videoCompatible = array("url" => $value, "poster" => $poster, "width" => $width, "height" => $height,
                        "title" => $title, "plugins" => false);
                    $this->flowplayer->videoCompatible($videoCompatible);
                }
            }
            $source = '<source src="' . $value . '" ' . $this->linkGen->getVideoType($value) . ' />';
            if (((preg_match("#.(ext|main).(mp4|m4v)$#i", $value) && $this->buggyiOS(self::maxBuggyIOSWebkitAlt) &&
                    !preg_match('#iPad#', $_SERVER['HTTP_USER_AGENT'])) ||
                    (preg_match("#.(ogv|ogg|webm|high\.(mp4|m4v))$#i", $value) && $this->buggyiOS(self::maxBuggyIOSWebkitAlt)))
                    && !$this->option['xmlMode']) {
                $source = '';
            }
            $sources .= $source;
        }
        $links = $outside = "";
        $novideo = $this->language['noVideo'] . "<br />";
        if ($this->mobileCheck() || $this->option['videoLinkOutside']) {
            $outside = $this->option['videoLinkOutsideBefore'] . $this->linkGen->getVideoLinks() .
                    $this->option['videoLinkOutsideAfter'];
        } else {
            $links = $this->linkGen->getVideoLinks();
        }
        if($this->option['downloadLinkDisabled']) {
            $novideo = "";
            $links = $outside = "";
        }
        $id = $this->getID($this->option['videoID'], "video");
        if($id != '') {
            $idAlt = 'id="'.$id.'"';
        } else {
            $idAlt = '';
        }
        $header = sprintf("%s<video %s %s %s %s %s>", $this->option['beforeVideo'],
                        $idAlt,
                        $this->getPoster($poster), $this->getResolutionCode($width, $height),
                        $this->getTitle($title), $this->getHtmlAttribute($attribute, "video"));
        $footer = "</video>";
        return sprintf('%s %s %s %s %s %s %s %s', $this->getJavaScriptCall($this->option['videoScript'], "video"), $header, $sources.$this->tracks($track),
                $this->getFallback($this->getPosterForFallback($poster) . $novideo . $links,
                        $oembed, "video", $lock), self::HTML5_TAG, $footer, $outside,
                $this->option['afterVideo'].$this->mediaElementConfig($id, $mediaelement, 'VIDEO'));
    }

    private function tracks($track) {
        try {
            if ($track) {
                $string = '';
                foreach ($track as $kind => $arrays) {
                    if($this->is_assoc($arrays)) {
                        $arrays = array($arrays);
                    }
                    foreach ($arrays as $data) {
                        foreach ($data as $attr => $src) {
                            $attribute[] = $attr . '="' . $src . '"';
                        }
                        $string .= '<track kind="' . $kind . '" ' . implode(" ", $attribute) . ' /> ';
                        unset($attribute);
                    }
                }
                return $string;
            } else {
                return "";
            }
        } catch (Exception $e) {
            return "";
        }
    }

    private function getID($name, $type) {
        if ($name) {
            $this->count[$type]++;
            return $name . '-' . $this->count[$type];
        } else {
            return "";
        }
    }

    private function getJavaScriptCall($script, $type) {
        if ($script && $this->option[$type . 'ID']) {
            $output = sprintf($script, $this->option[$type . 'ID'] . '-' . $this->count[$type]);
            return sprintf("<script type='text/javascript'>%s</script>", $output);
        } else {
            return "";
        }
    }

    private function getHtmlAttribute($attribute, $type) {
        $htmlAtrribute = $this->htmlAttribute[$type];
        if ($attribute) {
            foreach ($attribute as $key => $value) {
                unset($htmlAtrribute[strtolower($key)]);
                $htmlAtrribute[strtolower($key)] = $value;
            }
            unset($attribute);
        }

        // Unset banned Attribute Start
        unset($htmlAtrribute['id']);
        unset($htmlAtrribute['title']);
        unset($htmlAtrribute['width']);
        unset($htmlAtrribute['height']);
        unset($htmlAtrribute['poster']);
        unset($htmlAtrribute['src']);
        // Unset banned Attrbute End

        $htmlAttri = "";
        foreach ($htmlAtrribute as $key => $value) {
            if ($value == null) {
                $htmlAttri .= $key . " ";
            } else {
                $htmlAttri .= $key . '="' . htmlspecialchars($value) . '" ';
            }
        }
        return $htmlAttri;
    }

    private function getPosterForFallback($poster) {
        if ($poster) {
            return '<img src="' . $poster . '" /><br />';
        } else {
            return "";
        }
    }

    private function getPoster($poster) {
        if (!$poster || $this->buggyiOS()) {
            return "";
        }
        return 'poster="' . $poster . '"';
    }

    private function getTitle($title) {
        if ($title) {
            return 'title="' . $title . '"';
        }
        return "";
    }

    public function setFlowLocation($url) {
        $this->flowplayer->setFlowLocation($url);
    }

    private function buggyiOS($maxWebKitVersion = self::maxBuggyIOSWebkit) {
        if (preg_match('#(iPod|iPhone|iPad)#', $_SERVER['HTTP_USER_AGENT'])) {
            if (preg_match("#AppleWebKit/([0-9]+)(\.|\+|:space:)#", $_SERVER['HTTP_USER_AGENT'],
                            $matches)) {
                $WebKitVersion = (int) $matches[1];
                if ($WebKitVersion >= self::minBuggyIOSWebkit && $WebKitVersion < $maxWebKitVersion) {
                    return true;
                }
            }
        }
        return false;
    }

    private function getResolutionCode($width, $height) {
        if (!($width && $height)) {
            return "";
        }
        return 'width="' . $width . '" height="' . $height . '"';
    }

    public function audioreplace($data) {
        $audiourls = $data[1];
        $audiourls = explode("|", $audiourls);
        $audiourls = $this->urlsCheck($audiourls);
        return $this->audioCodeGenerator($audiourls);
    }

    public function audioreplaceJSON($data, $array = false, $lock = false) {
        if (preg_match("#(webOS|SymbianOS|Nokia|Android)#i", $_SERVER['HTTP_USER_AGENT']) &&
                (defined('WPHTML5_PREVENT_FLASH_LITE') && !$this->option['xmlMode'])) {
            $lock = true;
        }
        if ($array) {
            $jsonTemp = $array;
        } else {
            if (is_array($data)) {
                $jsonTemp = $this->removeJSONNoise($data[1]);
            } else {
                $jsonTemp = $data;
            }
            unset($data);
            $jsonTemp = json_decode($jsonTemp, true);
        }
        if ($this->is_assoc($jsonTemp)) {
            foreach ($jsonTemp as $key => $value) {
                $json[strtolower($key)] = $value;
            }
            unset($jsonTemp);
            if (isset($json["src"])) {
                $json["url"] = $json["src"];
                unset($json["src"]);
            }
            if (!isset($json["url"])) {
                return "ERROR: url not specified";
            } elseif ($this->is_assoc($json["url"]) && !is_string($json["url"])) {
                return "ERROR: url as object is not allowed";
            }
            if (!is_array($json["url"])) {
                $json['url'] = array($json['url']);
            }
            if (!isset($json["title"]) || is_array($json["title"])) {
                $json["title"] = false;
            } else {
                $json["title"] = htmlspecialchars($json["title"]);
            }
            if (!isset($json["attribute"])) {
                $json["attribute"] = false;
            } elseif (!$this->is_assoc($json["attribute"])) {
                $json["attribute"] = false;
            }
            if (isset($json["oembed"]) && !$this->is_assoc($json["oembed"]) && !$lock) {
                $temp = array(
                    "url" => $json["oembed"],
                    "width" => $json["width"],
                    "height" => $json["height"]
                );
                $json["oembed"] = $temp;
                unset($temp);
            } else {
                $json["oembed"] = false;
            }

            if (!isset($json["mediaelement"])) {
                $json["mediaelement"] = false;
            } elseif (!$this->is_assoc($json["mediaelement"])) {
                $json["mediaelement"] = false;
            }

            return $this->audioCodeGenerator(null, $json, $lock);
        } else {
            return $this->jsonError() . " @ Audio Tag";
        }
    }

    public function urlsCheck($urls) {
        $arrayCount = 0;
        foreach ($urls as $value) {
            $value = preg_replace("# $#i", "", $value);
            if (!preg_match("#^(http|https)://#i", $value)) {
                $data = $this->url['site'] . "/" . $value;
                $array[$arrayCount] = htmlspecialchars($data);
            } else {
                $array[$arrayCount] = htmlspecialchars($value);
            }
            $arrayCount++;
        }
        return $array;
    }

    private function audioCodeGenerator($audiourls, $JSON = false, $lock = false) {
        if ($JSON) {
            $audiourls = $this->urlsCheck($JSON['url']);
            $title = $JSON['title'];
            $attribute = $JSON["attribute"];
            $oembed = $JSON["oembed"];
            $mediaelement = $JSON["mediaelement"];
            unset($JSON);
        } else {
            $title = false;
            $attribute = false;
            $oembed = false;
            $mediaelement = false;
        }
        if (!isset($this->linkGen)) {
            $this->linkGen = new TypeAndLinkGenclass($this->language['downloadAudio'],
                    $this->language['downloadVideo'], $this->language['openFormat'], $this->language['closedFormat'],
                    $this->meEnabled());
        }
        $source = '';
        foreach ($audiourls as $value) {
            if (!($lock || $oembed)) {
                if($this->mediaelement) {
                    $audioCompatible = array("url" => $value, "title" => $title);
                    $this->mediaelement->audioCompatible($audioCompatible);
                } else {
                    $audioCompatible = array("url" => $value, "title" => $title, "plugins" => false);
                    $this->flowplayer->audioCompatible($audioCompatible);
                }
            }
            $source .='<source src="' . $value . '" ' . $this->linkGen->getAudioType($value) . ' />';
        }
        $links = $outside = "";
        $noaudio = $this->language['noAudio'] . "<br />";
        if ($this->mobileCheck() || $this->option['audioLinkOutside']) {
            $outside = $this->option['audioLinkOutsideBefore'] . $this->linkGen->getAudioLinks() .
                    $this->option['audioLinkOutsideAfter'];
        } else {
            $links = $this->linkGen->getAudioLinks();
        }
        if($this->option['downloadLinkDisabled']) {
            $noaudio = "";
            $links = $outside = "";
        }
        $id = $this->getID($this->option['audioID'], "audio");
        if($id != '') {
            $idAlt = 'id="'.$id.'"';
        } else {
            $idAlt = '';
        }
        $header = sprintf("%s<audio %s %s %s>", $this->option['beforeAudio'],
                        $idAlt,
                        $this->getTitle($title), $this->getHtmlAttribute($attribute, "audio"));
        $footer = "</audio>";
        return sprintf('%s %s %s %s %s %s %s %s', $this->getJavaScriptCall($this->option['audioScript'], "audio"),
                $header, $source, $this->getFallback($noaudio . $links,
                        $oembed, "audio", $lock), self::HTML5_TAG, $footer, $outside,
                $this->option['afterAudio'].$this->mediaElementConfig($id, $mediaelement, 'AUDIO'));
    }

    private function getFallback($fallback, $oembed, $type, $lock) {
        if (!$lock) {
            if ($oembed && class_exists('WP_Embed')) {
                $url = $oembed['url'];
                $this->oembed->parseUrl($url);
                unset($oembed['url']);
                if (($oembed['width'] && $oembed['height'])) {
                    $this->oembed->setWidth($oembed['width']);
                    $this->oembed->setHeight($oembed['height']);
                }
                $this->flowplayer->setOptions("flashIsSetup", false);
                if($this->mediaelement) {
                    $this->mediaelement->setOptions("flashIsSetup", false);
                }
                $this->oembed->setFallback($fallback);
                return $this->oembed->getEmbedCode();
            } else {
                if($this->mediaelement) {
                    if ($this->mediaelement->getFlashIsSetup()) {
                        return $this->mediaelement->getFlashObject($fallback);
                    } else {
                        return $fallback;
                    }
                } else {
                    if ($this->flowplayer->getFlashIsSetup()) {
                        return $this->flowplayer->getFlashObject($fallback);
                    } else {
                        return $fallback;
                    }
                }
            }
        } else {
            $this->flowplayer->setOptions("flashIsSetup", false);
            if ($this->mediaelement) {
                $this->mediaelement->setOptions("flashIsSetup", false);
            }
            return $fallback;
        }
    }

    private function mobileCheck() {
        if (preg_match("#(Opera Mini|Opera Mobi)#", $_SERVER['HTTP_USER_AGENT']) ||
                (preg_match('#((webOS|SymbianOS|Nokia)+?AppleWebKit|AppleWebKit(.*?)Mobile)#', $_SERVER['HTTP_USER_AGENT']) &&
                !preg_match('#iPad#', $_SERVER['HTTP_USER_AGENT']))) {
            return true;
        } else {
            return false;
        }
    }

    private function meEnabled() {
        if($this->mediaelement) {
            return true;
        } else {
            return false;
        }
    }

    private function mediaElementConfig($id, $config, $type) {
        if(!$config || !$this->meEnabled()) {
            return "";
        }

        if(defined("HTML5FRAMEWORK_ME_CONFIG_".$type)) {
            $temp = constant("HTML5FRAMEWORK_ME_CONFIG_".$type);
            $temp = json_decode($temp, true);
            if (!isset($temp["features"])) {
                $temp["features"] = array(
                    'playpause',
                    'progress',
                    'current',
                    'duration',
                    'tracks',
                    'volume',
                    'fullscreen'
                );
            }
            if($this->is_assoc($temp)) {
                $config = array_merge_recursive($temp, $config);
            }
            unset($temp);
            if(isset($config["disabledfeatures"])) {
                $kills = array();
                foreach($config["disabledfeatures"] as $disabledFeature) {
                    foreach($config["features"] as $key => $feature) {
                        if($feature == $disabledFeature) {
                            $kills[] = $key;
                            break;
                        }
                    }
                }
                foreach($kills as $kill) {
                    unset($config["features"][$kill]);
                }
            }
            unset($config["disabledfeatures"]);
        }
        return '<script type="text/javascript">jQuery(\'#'.$id.'\').mediaelementplayer('.json_encode($config).');</script>';
    }
}